<script setup lang="ts">
import { h, onMounted, reactive, ref } from 'vue';
import type { DataTableColumns } from 'naive-ui';
import { NButton, NSpace, NTooltip, useDialog } from 'naive-ui';
import { onBeforeRouteLeave, useRoute } from 'vue-router';
import mammoth from 'mammoth';
import _ from 'underscore';
import { ChevronBack } from '@vicons/ionicons5';
import { useBoolean } from '~/packages/hooks';
import {
  convertImageToBase64,
  errorMessage,
  escapeHTMLManually,
  generateRandomCode,
  getImageInfoByUrl,
  getImageInfoFromBase64,
  infoMessage,
  sliceStringByLength,
  successMessage,
  warningMessage
} from '@/utils/utils';
import {
  generateContent,
  getEditDataInfoAction,
  getLogCatalogAction,
  htmlToDocAction,
  insertCatalogDataAction,
  latestCatalogDataAction,
  msgCheckAction,
  stepGenerateAction
} from '@/service/api';
import CompletedWritingImg from '@/assets/imgs/icon-completed-writing.png';
import NotWritingImg from '@/assets/imgs/icon-not-written.png';
import { useRouterPush } from '@/hooks/common/router';
import FormatModal from '@/views/document/preview/modules/format-modal.vue';
import DownloadModal from '@/views/document/preview/modules/download-modal.vue';
import WritingImg from '@/assets/imgs/icon-writing.png';
import WritingDirectionModal from '@/views/document/preview/modules/writing-direction-modal.vue';
import SelectImageDrawer from '@/views/document/preview/modules/select-image-drawer.vue';
import { localStg } from '@/utils/storage';
import KnowledgeModal from "@/views/document/preview/modules/knowledge-modal.vue";

const { bool: showFormatModal, setTrue: openFormatModal } = useBoolean();
const { bool: showDownloadModal, setTrue: openDownloadModal } = useBoolean();
const { bool: showDirectionModal, setTrue: openDirectionModal } = useBoolean();
const { bool: showImageDrawer, setTrue: openImageDrawer } = useBoolean();
const { bool: showKnowledgeDrawer, setTrue: openKnowledgeDrawer } = useBoolean();

const { query } = useRoute();
const { routerBack } = useRouterPush();

const { VITE_SERVICE_BASE_URL, VITE_OTHER_SERVICE_BASE_URL } = import.meta.env;
const otherUrl = JSON.parse(VITE_OTHER_SERVICE_BASE_URL);

// 是否一键编写
const isOneClickWrite = ref<boolean>(false);
const writingNum = ref<number>(0); // 编写中数量

const isBack = ref<boolean>(false);
const generateType = ref<number>(0); // 生成类型 0：正常生成；1：编辑
const taskId = ref<any>(3); // 任务Id
const paragraphId = ref<any>(); // 段落Id
const infoPath = ref<any>(''); // 模板信息文档地址
const zhaoBiaoPath = ref<any>(''); // 招标文件地址（新建上传的）
const catalogPath = ref<any>(''); // 生成的目录文件地址
const knowledgeId = ref<any>(''); // 选取的知识库Id
const writeContentHtml = ref<string>('');
const imgList = ref<any[]>([]);
const IMAGE_TAG: string = 'WRITE_IMAGE_TAG';
const fileName = ref<any>('某某项目建设项目');
const catalogList = ref<any[]>([]);
const catalogRowKeys = ref<any[]>([]);
const currentFormat = ref<number>(1); // 当前选中的版本
const showLoading = ref<boolean>(true);
const loadingDes = ref<string>('正在努力处理中，请稍后...');
const docInfoObj = ref<any>({
  catalogNum: 0, // 总目录数
  finishNum: 0, // 已编写字数
  waitNum: 0, // 待编写
  wordNum: 0 // 文档总字数
}); // 文档基本信息

const writeTagList = ref<any[]>([
  { id: generateRandomCode(6), title: '已完成', color: '#68BF7B', image: CompletedWritingImg },
  { id: generateRandomCode(6), title: '未编写', color: '#C0C0C0', image: NotWritingImg },
  { id: generateRandomCode(6), title: '编写中', color: '#AE95FF', image: WritingImg }
]);

const formatOptions = ref<any[]>([
  {
    label: '当前版本',
    value: 1,
    filePath: '',
    tips: ''
  }
]);

const selectFormat = ref<any>({
  label: '当前版本',
  value: 1,
  filePath: '',
  tips: ''
});

onMounted(() => {
  // console.log('query: ', query);
  generateType.value = Number.parseInt(query.generateType as string, 10);
  taskId.value = Number.parseInt(query.taskId as string, 10);
  paragraphId.value = Number.parseInt(query.paragraphId as string, 10);
  fileName.value = query.fileName;
  infoPath.value = query.infoPath;
  zhaoBiaoPath.value = query.zhaoBiaoPath;
  catalogPath.value = query.catalogPath;

  // getHtmlByDocument();
  getLogCatalogData();
  queryEditDataInfo();
});

const ueditor = ref<any | null>(null);
const contentHtml = ref<string>('');

// 编辑器配置
const editorConfig: object = reactive({
  UEDITOR_HOME_URL: '/modules/bidWriting/UEditorPlus/',
  UEDITOR_CORS_URL: '/modules/bidWriting/UEditorPlus/',
  serverUrl: `${VITE_SERVICE_BASE_URL}/ueditor/config`,
  loadConfigFromServer: true,
  catcherActionName: 'catch',
  serverResponsePrepare(res) {
    console.log('文件上传res: ', res);
    // original: "avatar.jpg"
    // size: "4676"
    // state: "SUCCESS"
    // title: "1725521194151.jpg"
    // type: ".jpg"
    // url: "/pics/ueditor/2024/0905/1725521194151.jpg"
    if (res.state && res.state === 'SUCCESS') {
      getImageInfoByUrl(`${otherUrl.docImgUrl}${res.url}`, (info: any) => {
        if (info) {
          convertImageToBase64(`${otherUrl.docImgUrl}${res.url}`)
            .then(base64 => {
              ueditor.value.execCommand(
                'inserthtml',
                `<p style="display: block;text-align: center;"><img src="${base64}" alt="${res.title}" width="${info.width}" height="${info.height}"/></p>`
              );
            })
            .catch(error => {
              console.error('转换失败：', error);
            });
        } else {
          console.log('无法获取图片信息');
          convertImageToBase64(`${otherUrl.docImgUrl}${res.url}`)
            .then(base64 => {
              ueditor.value.execCommand(
                'inserthtml',
                `<p style="display: block;text-align: center;"><img src="${base64}" alt="${res.title}" width="90%" height="auto"/></p>`
              );
            })
            .catch(error => {
              console.error('转换失败：', error);
            });
        }
      });
      return {
        original: '',
        size: '0',
        state: 'SUCCESS',
        title: '1.jpg',
        type: '.jpg',
        url: ''
      };
    }
    // 这里返回的结果需要是 UEditor 原始需要的数据结构
    return res;
  },
  imageConfig: {
    // 禁止本地上传
    disableUpload: false,
    // 禁止在线管理
    disableOnline: true,
    // 自定义选择按钮
    selectCallback: null
  },
  toolbars: [
    [
      'fullscreen',
      'undo',
      'redo',
      '|',
      'bold',
      'italic',
      'underline',
      'fontborder',
      'strikethrough',
      'superscript',
      'subscript',
      'removeformat',
      'formatmatch',
      'autotypeset',
      'blockquote',
      'pasteplain',
      '|',
      'forecolor',
      'backcolor',
      'insertorderedlist',
      'insertunorderedlist',
      'selectall',
      'cleardoc',
      '|',
      'rowspacingtop',
      'rowspacingbottom',
      'lineheight',
      '|',
      'customstyle',
      'paragraph',
      'fontfamily',
      'fontsize',
      '|',
      'directionalityltr',
      'directionalityrtl',
      'indent',
      '|',
      'justifyleft',
      'justifycenter',
      'justifyright',
      'justifyjustify',
      '|',
      'touppercase',
      'tolowercase',
      '|',
      'link',
      'unlink',
      'anchor',
      '|',
      'imagenone',
      'imageleft',
      'imageright',
      'imagecenter',
      '|',
      // 'insertimage',
      // 'emotion',
      // 'scrawl',
      // 'insertvideo',
      // 'music',
      // 'attachment',
      // 'map',
      // 'gmap',
      // 'insertframe',
      // 'insertcode',
      // 'webapp',
      // 'pagebreak', // 分页
      // 'template',  // 模板
      // 'background',  // 背景
      // '|',
      'horizontal',
      // 'date',
      // 'time',
      'spechars',
      'snapscreen',
      // 'wordimage', // 图片转存（需要配置图片上传服务器）
      '|',
      'inserttable',
      'deletetable',
      'insertparagraphbeforetable',
      'insertrow',
      'deleterow',
      'insertcol',
      'deletecol',
      'mergecells',
      'mergeright',
      'mergedown',
      'splittocells',
      'splittorows',
      'splittocols',
      'charts',
      '|',
      // 'preview', // 预览
      // 'searchreplace',
      'drafts',
      'simpleupload',
      'expand', // AI扩写
      'abbreviate', // AI缩写
      'continuation', // AI续写
      'retouch', // AI润色
      'databaseimage' // 资料库图片
    ]
  ],
  autoFloatEnabled: false,
  autoSaveEnable: false, // 禁用自动保存
  elementPathEnabled: false, // 禁用元素路径
  initialFrameHeight: '445',
  autoHeightEnabled: false, // 禁止编辑器自动长高
  maximumWords: 1000000,
  zIndex: 900
});

// 引入的js文件，这里是一定要写的。
const editorDependencies: string[] = reactive(['ueditor.config.js', 'ueditor.all.js', 'lang/zh-cn/zh-cn.js']);

function readyHandle(editor: any) {
  ueditor.value = editor;

  // 监听内容变化
  // editor.addListener('contentchange', (res: any) => {
  //   console.log('编辑器内容发生改变: ', res);
  // });

  /** expand: 扩写 abbreviate: 缩写 */
  // 扩写
  ueditor.value.commands.expand = {
    execCommand(cmd: string, format: any) {
      contentGenerate(cmd);
    }
  };
  // 缩写
  ueditor.value.commands.abbreviate = {
    execCommand(cmd: string, format: any) {
      contentGenerate(cmd);
    }
  };
  // 续写
  ueditor.value.commands.continuation = {
    execCommand(cmd: string, format: any) {
      contentGenerate(cmd);
    }
  };
  // 润色
  ueditor.value.commands.retouch = {
    execCommand(cmd: string, format: any) {
      contentGenerate(cmd);
    }
  };
  // 资料库图片
  ueditor.value.commands.databaseimage = {
    execCommand(cmd: string, format: any) {
      openImageDrawer();
    }
  };

  queryLatestCatalogData(paragraphId.value);
}

// 改写/扩写/缩写/润色内容生成
function contentGenerate(type: string) {
  // 获取选中的内容
  let selectionText: string = '';
  // 获取当前选中的文本
  const selection = ueditor.value.selection.getRange();
  selection.select();
  selectionText = ueditor.value.selection.getText();

  if (selectionText.length === 0) {
    warningMessage('请先选择要处理的文本内容');
    return;
  }

  let typeStr;
  switch (type) {
    case 'expand': // 扩写
      typeStr = '扩写';
      break;
    case 'abbreviate': // 缩写
      typeStr = '缩写';
      break;
    case 'continuation': // 续写
      typeStr = '续写';
      break;
    case 'retouch': // 润色
      typeStr = '润色';
      break;
    default:
      typeStr = '润色';
      break;
  }

  loadingDes.value = 'AI正在努力处理中，请稍后...';
  showLoading.value = true;
  const params: any = {
    query: `请将以下文段${typeStr}：${selectionText}`, // 需要组合prompt
    conversation_id: '523453452545234245', // 默认随机传即可
    history_len: -1,
    history: [],
    stream: false, // 流式返回
    model_name: 'doubao-pro-32k', // doubao-pro-32k
    temperature: 0.7,
    max_tokens: 0,
    prompt_name: 'default'
  };
  generateContent(params).then((res: any) => {
    // console.log(res.text);
    let chatStr: string = res.text;
    chatStr = chatStr.replace(/\r\n|\r|\n/g, '<br/>');
    ueditor.value.execCommand('inserthtml', `<span style="background-color: #D7F0FF">${chatStr}</span>`); // 插入文本
    showLoading.value = false;
  });
}

// 查询目录树
async function getLogCatalogData() {
  showLoading.value = true;
  const { data, error } = await getLogCatalogAction(taskId.value);
  showLoading.value = false;
  if (!error) {
    catalogList.value = data || [];

    writingNum.value = 0;
    getDefaultSelectCatalog(catalogList.value);
    queryWritingStatusContent(catalogList.value);
    isOneClickWrite.value = writingNum.value > 0;

    // 清空所有展开树
    catalogRowKeys.value = [];
    // 默认所有目录全部展开
    getAllCatalogKeys(catalogList.value);
  }
}

// 设置所有需要展开的目录
function getAllCatalogKeys(catalogs: any[]) {
  catalogs.forEach(item => {
    item.code = generateRandomCode(8);
    catalogRowKeys.value.push(item.id);

    if (item.children && item.children.length > 0) {
      getAllCatalogKeys(item.children);
    }
  });
}

// 查询是否有编写中的内容
function queryWritingStatusContent(catalogs: any[]) {
  catalogs.forEach(item => {
    if (item.status === 2) {
      writingNum.value += 1;
    }

    if (item.children && item.children.length > 0) {
      queryWritingStatusContent(item.children);
    }
  });
}

const selectItem = ref<RowData>({
  ancestors: '',
  children: undefined,
  createTime: '',
  logId: 0,
  more3: '',
  parentId: 0,
  rankId: 0,
  status: 0,
  title: fileName.value,
  type: 0,
  id: paragraphId.value,
  tips: ''
});

// 获取默认选中的章节
function getDefaultSelectCatalog(catalogs: any[]) {
  catalogs.forEach(item => {
    if (item.id === paragraphId.value) {
      selectItem.value = item;
      return;
    }

    if (item.children && item.children.length > 0) {
      getDefaultSelectCatalog(item.children);
    }
  });
}

const knowledgeStr = ref<string>('');

// 查询目录对应的内容
async function queryLatestCatalogData(catalogId: number) {
  const params: any = {
    catalogId
  };
  const { data, error } = await latestCatalogDataAction(params);
  console.log('data: ', data);
  if (!error) {
    if (data && data.filePath) {
      formatOptions.value = [];
      knowledgeStr.value = data.more1 ? data.more1 : '';
      getHtmlByDocument(data.filePath);
      const formatObj: any = {
        label: '当前版本',
        value: 1,
        filePath: data.filePath,
        tips: selectItem.value.tips
      };
      formatOptions.value.push(formatObj);
      selectFormat.value = formatObj;
      currentFormat.value = 1;
    } else {
      ueditor.value.clear();
    }
  }
}

// 获取标书编辑数据
async function queryEditDataInfo() {
  const { data, error } = await getEditDataInfoAction(taskId.value);
  if (!error) {
    /** catalogNum :125 //总目录数 finishNum: 1 // 已编写字数 waitNum: 124 // 待编写 wordNum: 2352 // 文档总字数 */
    docInfoObj.value = data;
    knowledgeId.value = data.knowledgeName;
  }
}

// 根据文档获取html内容
function getHtmlByDocument(filePath: string) {
  const docPath: string = otherUrl.fileUrl + filePath;
  loadingDes.value = '文档较大，正在努力处理中，请稍后...';
  showLoading.value = true;
  fetch(docPath, { cache: 'no-cache' })
    .then(response => response.blob())
    .then(blobData => {
      let file: File | null = new File([blobData], `${fileName.value}.docx`, {
        type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        lastModified: Date.now()
      });

      analysisWord(file).then(html => {
        // console.log("html: ", html);
        for (let i: number = 0; i < imgList.value.length; i++) {
          writeContentHtml.value = writeContentHtml.value.replace(IMAGE_TAG, imgList.value[i]);
        }
        writeContentHtml.value = writeContentHtml.value.replace(/style=""/g, '');
        // 设置内容到编辑器中
        ueditor.value.setContent(writeContentHtml.value, false);
        showLoading.value = false;
        // ueditor.value.execCommand('inserthtml', writeContentHtml.value); // 插入文本
      });

      // 文件信息置空
      file = null;
      showLoading.value = false;
    })
    .catch(error => {
      console.error('发生错误：', error);
      showLoading.value = false;
      errorMessage('获取文档失败');
    });
}

// 解析word文件，将word转为html
function analysisWord(file: any) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = evt => {
      // 当文件读取完毕后
      // p标签首行没有缩进
      const options = {
        transformDocument: transformElement,
        styleMap: ["p[style-name='Section Title'] => h1:fresh", "p[style-name='Subsection Title'] => h2:fresh"]
      };

      // 调用mammoth组件的方法进行解析文件
      mammoth
        .convertToHtml({ arrayBuffer: evt.target!.result }, options)
        .then(async resultObject => {
          // console.log("resultObject: ", resultObject);
          // resultObject.value = imgTagAddStyle(resultObject.value);
          const imgSrcReg = /<img[^>]+src=[\\'|\\"]?([^(?"|?'|?>)]+)[\\'|\\"]?[^>]*>/gim;
          const imgSrcList = resultObject.value.match(imgSrcReg);

          for (let i: number = 0; i < imgSrcList?.length; i++) {
            const imgSrc: string = imgSrcList[i].match(/src="(.+?)"/)[1];

            // console.log('imgSrc: ', imgSrc);
            const info = await getImageInfoFromBase64(imgSrc);
            if (info) {
              imgSrcList[i] =
                `${imgSrcList[i].substring(0, imgSrcList[i].length - 2)}width="${info.width}" height="${info.height}" ${imgSrcList[i].substring(imgSrcList[i].length - 2)}`;
            } else {
              imgSrcList[i] =
                `${imgSrcList[i].substring(0, imgSrcList[i].length - 2)}width="90%" height="auto" ${imgSrcList[i].substring(imgSrcList[i].length - 2)}`;
            }

            // 使用DOM解析器创建一个DOM元素
            // const domParser = new DOMParser();
            // const contentDom = domParser.parseFromString(imgSrcList[i], 'text/html');
            // const imgNode = contentDom.body.childNodes;
            //
            // console.log('imgNode: ', imgNode);
          }

          if (imgSrcList) {
            imgList.value = imgSrcList;
          }

          // console.log('imgList: ', imgList.value);
          resolve(resultObject.value); // 将处理好的html数据返回
          reader.abort(); // 关闭读取
        })
        .catch(err => {
          console.log('err: ', err);
          reader.abort(); // 关闭读取
        });
    };
    reader.readAsArrayBuffer(file);
    // 启动读取指定的 Blob 或 File 内容：https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsArrayBuffer
  });
}

// 元素重新定义
function transformElement(element: any) {
  if (element.children) {
    const children: any = _.map(element.children, transformElement);
    element = { ...element, children };
  }

  if (element.type === 'paragraph') {
    element = transformParagraph(element);
  }

  // console.log('element：', element);

  if (element.type === 'document') {
    // docParagraphList.value = element.children;
    // console.log('docParagraphList.value: ', element.children);

    htmlFormat(element.children);
  }

  return element;
}

// 段落内容重新定义
function transformParagraph(element: any) {
  if (element.alignment === 'center' && !element.styleId) {
    return { ...element, styleId: 'Heading2' };
  }
  return element;
}

// 根据文档解析API进行HTML内容拼接封装
function htmlFormat(docParagraphList: any[]) {
  let docHtmlStr: string = '';
  for (let i: number = 0; i < docParagraphList.length; i++) {
    const paragraphObj: any = docParagraphList[i];
    if (paragraphObj.type === 'paragraph') {
      // 普通段落内容（包括文字和图片）
      let paragraphStr: string = '';
      let alignmentStr: string = '';
      if (paragraphObj.alignment) {
        alignmentStr = `text-align: ${paragraphObj.alignment}; line-height: 1.5; align-items: baseline;`;
      } else {
        alignmentStr = 'text-align: left; line-height: 1.5; align-items: baseline;';
      }

      for (let j: number = 0; j < paragraphObj.children.length; j++) {
        if (paragraphObj.children.length > 1 && j === 0 && paragraphObj.indent.firstLine) {
          alignmentStr += 'text-indent: 2em;';
        }
        const formatContent = paragraphHtmlFormat(paragraphObj.children[j]);
        if (formatContent === IMAGE_TAG) {
          alignmentStr = 'display: block;text-align: center;';
        }
        paragraphStr += formatContent;
      }
      if (paragraphObj.styleId === 'Heading1' || paragraphObj.styleName === 'heading 1') {
        docHtmlStr += `<h1 style="${alignmentStr}">${paragraphStr}</h1>`;
      } else if (paragraphObj.styleId === 'Heading2' || paragraphObj.styleName === 'heading 2') {
        docHtmlStr += `<h2 style="${alignmentStr}">${paragraphStr}</h2>`;
      } else if (paragraphObj.styleId === 'Heading3' || paragraphObj.styleName === 'heading 3') {
        docHtmlStr += `<h3 style="${alignmentStr}">${paragraphStr}</h3>`;
      } else if (paragraphObj.styleId === 'Heading4' || paragraphObj.styleName === 'heading 4') {
        docHtmlStr += `<h4 style="${alignmentStr}">${paragraphStr}</h4>`;
      } else if (paragraphObj.styleId === 'Heading5' || paragraphObj.styleName === 'heading 5') {
        docHtmlStr += `<h5 style="${alignmentStr}">${paragraphStr}</h5>`;
      } else if (paragraphObj.styleId === 'Heading6' || paragraphObj.styleName === 'heading 6') {
        docHtmlStr += `<h6 style="${alignmentStr}">${paragraphStr}</h6>`;
      } else {
        docHtmlStr += `<p style="${alignmentStr}">${paragraphStr}</p>`;
      }
    } else if (paragraphObj.type === 'table') {
      // 表格内容处理
      const tableObj: any = docParagraphList[i];
      docHtmlStr += tableHtmlFormat(tableObj);
    }
  }
  writeContentHtml.value = `<div style="margin: 72pt;">${docHtmlStr}</div>`;
}

// 段落内容格式化
function paragraphHtmlFormat(paragraphObj: any) {
  let contentStr: string = '';

  // console.log("paragraphObj: ", paragraphObj);

  if (!paragraphObj.children) {
    return '<span></span>';
  }

  if (paragraphObj.children.length === 0) {
    return '<br/>';
  }

  for (let i: number = 0; i < paragraphObj.children.length; i++) {
    if (paragraphObj.children[i].type === 'text') {
      let textStr: string = paragraphObj.children[i].value;
      // 如果有html字符串，将其解析为html字符串，就可以正常展示
      textStr = escapeHTMLManually(textStr);

      let styleStr: string = `line-height: 150%;`;
      if (paragraphObj.font) {
        styleStr += `font-family: ${paragraphObj.font};`;
      }
      if (paragraphObj.fontSize) {
        styleStr += `font-size: ${paragraphObj.fontSize}pt;`;
      }
      // 是否有下划线
      if (paragraphObj.isUnderline) {
        styleStr += 'text-decoration: underline;';
      }
      // 是否有删除线
      if (paragraphObj.isStrikethrough) {
        styleStr += 'text-decoration: line-through;';
      }
      // if (paragraphObj.verticalAlignment) {
      //   styleStr += `display: block; align-items: ${paragraphObj.verticalAlignment};`;
      // }
      /** font: "fzxbsjw-gb1-0" fontSize: 32 */
      // 文档标题设置固定的色值：#E03E2D
      if (paragraphObj.fontSize === 32 && paragraphObj.font === 'fzxbsjw-gb1-0') {
        styleStr += 'color: #E03E2D;';
      }
      // 是否加粗(使用 strong 标签加粗内容)
      if (paragraphObj.isBold) {
        styleStr += 'font-weight: bold;';
      }
      contentStr += `<span style="${styleStr}">${textStr}</span>`;
    } else if (paragraphObj.children[i].type === 'break') {
      // 换行
      contentStr += '<br/>';
    } else if (paragraphObj.children[i].type === 'image') {
      // 图片
      contentStr += IMAGE_TAG;
    } else {
      contentStr = String(contentStr);
    }
  }

  return contentStr;
}

// 表格内容格式化
function tableHtmlFormat(tableObj: any) {
  let tableStr: string = '';
  for (let i: number = 0; i < tableObj.children.length; i++) {
    // 遍历 tableRow
    const rowObj: any = tableObj.children[i];
    if (rowObj.isHeader) {
      tableStr += '<thead><tr>';
    } else {
      tableStr += '<tbody><tr>';
    }
    for (let j: number = 0; j < rowObj.children.length; j++) {
      // 遍历 tableCell
      const cellObj: any = rowObj.children[j];
      if (rowObj.isHeader) {
        tableStr += `<th>`;
      } else {
        tableStr += `<td>`;
      }
      for (let k: number = 0; k < cellObj.children.length; k++) {
        const contentObj: any = cellObj.children[k];

        let paragraphStr: string = '';
        let alignmentStr: string = '';
        if (contentObj.alignment) {
          alignmentStr = `text-align: ${contentObj.alignment};`;
        } else {
          alignmentStr = 'text-align: left;';
        }
        for (let l: number = 0; l < contentObj.children.length; l++) {
          if (contentObj.children.length > 1 && l === 0 && contentObj.indent && contentObj.indent.firstLine) {
            alignmentStr += 'text-indent: 2em;';
          }
          paragraphStr += paragraphHtmlFormat(contentObj.children[l]);
        }
        tableStr += `<p style="${alignmentStr}">${paragraphStr}</p>`;
      }
      if (rowObj.isHeader) {
        tableStr += '</th>';
      } else {
        tableStr += '</td>';
      }
    }
    if (rowObj.isHeader) {
      tableStr += '</tr></thead>';
    } else {
      tableStr += '</tr></tbody>';
    }
  }
  return `<table style="width: 100%; border-collapse: collapse;">${tableStr}</table>`;
}

// 插入资料库文件图片
function insertFolderImageAction(imageList: any[]) {
  imageList.forEach((item: any) => {
    // otherUrl.imgUrl + item.filePath
    getImageInfoByUrl(otherUrl.docImgUrl + item.filePath, (info: any) => {
      if (info) {
        convertImageToBase64(otherUrl.docImgUrl + item.filePath)
          .then(base64 => {
            ueditor.value.execCommand(
              'inserthtml',
              `<p style="display: block;text-align: center;"><img src="${base64}" alt="" width="${info.width}" height="${info.height}"/></p>`
            );
          })
          .catch(error => {
            console.error('转换失败：', error);
          });
      } else {
        console.log('无法获取图片信息');
        convertImageToBase64(otherUrl.docImgUrl + item.filePath)
          .then(base64 => {
            ueditor.value.execCommand(
              'inserthtml',
              `<p style="display: block;text-align: center;"><img src="${base64}" alt="" width="90%" height="auto"/></p>`
            );
          })
          .catch(error => {
            console.error('转换失败：', error);
          });
      }
    });
  });
}

// 修改编写样式
function changeDirectionClick() {
  openDirectionModal();
}

// 查看知识库引用
function lookKnowledgeClick() {
  openKnowledgeDrawer();
}

type RowData = {
  id: number;
  title: string;
  createTime: string;
  rankId: number;
  parentId: number;
  logId: number;
  type: number;
  status: number;
  more3: string;
  ancestors: string;
  children: any;
  tips: string;
};

const columns: DataTableColumns<RowData> = [
  {
    title: '章节名称',
    key: 'title',
    align: 'left',
    ellipsis: true,
    render(item: RowData) {
      let titleStyle: any = {};
      if (item.type === 1) {
        titleStyle = {
          fontFamily: 'HarmonyOS Sans SC',
          fontWeight: 'bold',
          fontSize: '20px',
          color: '#333333',
          cursor: 'pointer',
          display: 'block',
          maxWidth: '440px',
          whiteSpace: 'nowrap',
          overflow: 'hidden',
          textOverflow: 'ellipsis'
        };
      } else {
        titleStyle = {
          fontFamily: 'HarmonyOS Sans SC',
          fontWeight: '400',
          fontSize: '18px',
          color: '#666666',
          cursor: 'pointer',
          display: 'block',
          maxWidth: '440px',
          whiteSpace: 'nowrap',
          overflow: 'hidden',
          textOverflow: 'ellipsis'
        };
      }
      return h(
        NSpace,
        { justify: 'start', align: 'center', inline: true },
        {
          default: () => [
            h(
              NTooltip,
              { contentStyle: { maxWidth: '600px' } },
              {
                trigger: () => h('span', { style: titleStyle }, item.title),
                default: () =>
                  h(
                    'span',
                    {},
                    {
                      default: () => item.title
                    }
                  )
              }
            ),
            item.type !== 1 &&
              h('img', {
                height: 19,
                width: 19,
                src: item.status === 1 ? NotWritingImg : item.status === 3 ? CompletedWritingImg : WritingImg,
                alt: ''
              })
          ]
        }
      );
    }
  }
];

// 目录折叠展开
function expandedRowKeysUpdate(keys: Array<string | number>) {
  catalogRowKeys.value = keys;
}

const selectedRowKeysUpdate = (item: any) => {
  // const bgColor: string = (item.id === selectItem.value.id) ? 'rgba(131, 111, 255, 0.15)' : '#ffffff';
  // background-color: ${bgColor};
  return {
    style: `cursor: pointer;`,
    onClick: () => {
      // 已编写的可以查询内容
      if (item.status === 1) {
        infoMessage('该章节尚未撰写内容');
      } else if (item.status === 3) {
        selectItem.value = item;
        queryLatestCatalogData(item.id);
      } else {
        infoMessage('该章节尚未完成内容撰写');
      }
    }
  };
};

// 设置格式并预览
function setFormatAndPreviewClick() {
  openFormatModal();
}

const formatObj = ref<any>();

// 保存样式设置
function saveFormatSettingHandle(format: any) {
  console.log('设置好的样式：', format);
  formatObj.value = format;

  openDownloadModal();
}

// 版本选择
function formatChange(value: any) {
  console.log('value: ', value);
  for (let i: number = 0; i < formatOptions.value.length; i++) {
    if (value === formatOptions.value[i].value) {
      selectFormat.value = formatOptions.value[i];
    }
  }
  console.log('selectFormat: ', selectFormat.value);
  getHtmlByDocument(selectFormat.value.filePath);
}

const prompt = ref<string>('');

// 重新编写
async function rewriteClick() {
  const params: any = {
    task_id: taskId.value,
    tenant_id: knowledgeId.value,
    zhaobiao_path: zhaoBiaoPath.value,
    info_path: infoPath.value.split(','),
    title: selectItem.value.title,
    user_prompt: prompt.value
  };

  loadingDes.value = '小主，您的内容正在AI生成中，预计1分钟内完成，请稍后~';
  showLoading.value = true;
  const { data, error } = await stepGenerateAction(params);
  showLoading.value = false;
  if (!error) {
    if (data) {
      getHtmlByDocument(data.doc_path);
      const oldObj: any = formatOptions.value[0];
      oldObj.label = '上一个版本';
      formatOptions.value.splice(0, 1, oldObj);
      const newObj: any = {
        label: '当前版本',
        value: 2,
        filePath: data.doc_path,
        tips: prompt.value
      };
      if (formatOptions.value.length === 1) {
        formatOptions.value.push(newObj);
      } else {
        formatOptions.value.splice(1, 1, newObj);
      }
      currentFormat.value = 2;
    }
  }
}

// 保存编写方向
function saveTipsHandle(tips: string) {
  console.log('tips: ', tips);
  for (let i = 0; i < formatOptions.value.length; i++) {
    const formatObj: any = formatOptions.value[i];
    if (formatObj.value === currentFormat.value) {
      formatObj.tips = tips;
      formatOptions.value.splice(i, 1, formatObj);
      // selectFormat.value = formatObj;
    }
  }

  selectFormat.value = formatOptions.value[currentFormat.value - 1];
  prompt.value = tips;
}

const dialog = useDialog();

// 保存
async function saveClick() {
  const checkParams: any = {
    moduleValue: localStg.get('moduleId') || 1,
    keyword: ueditor.value.getContentTxt()
  };

  const { data: checkData, error: checkError } = await msgCheckAction(checkParams);
  if (!checkError) {
    if (checkData && checkData.length > 0) {
      dialog.error({
        title: '温馨提示',
        content: `内容详情中包含以下敏感词：\n${checkData.join('，')}`,
        style: 'white-space: pre-line;',
        positiveText: '确认'
      });
      return;
    }
  }

  let htmlContentStr: string = ueditor.value.getContent();

  const allImages: any = getAllImagesInEditor();
  // console.log('allImages: ', allImages);
  if (allImages.length > 0) {
    // 正确的做法 - 如果不需要并行处理
    const promises = allImages.map(async imageTag => {
      // const imageSrc = 'https://img2.baidu.com/it/u=2747638305,3937495153&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=639';
      const result = await convertImageToBase64(imageTag.src);
      if (result) {
        // console.log('result:', result);
        // imageTag.src = result;
        htmlContentStr = htmlContentStr.replace(
          `<img src="${imageTag.src}" alt="${imageTag.alt}"/>`,
          `<img src="${result}" alt="${imageTag.alt}" width="${imageTag.clientWidth}" height="${imageTag.clientHeight}"/>`
        );
      }
    });
    await Promise.all(promises);
  }

  // console.log('htmlContentStr: ', htmlContentStr);

  // htmlContentStr = htmlContentStr.replace(/<img /g, '<img width="650" height="650"');
  // 设置表格边框
  const htmlContent = htmlContentStr.replaceAll(/<table/g, `<table border-collapse="collapse" border="1" `);

  const saveParams: any = {
    contentList: sliceStringByLength(`<div>${htmlContent}</div>`, 40000)
  };

  loadingDes.value = '保存中，请稍后...';
  showLoading.value = true;
  const { data, error } = await htmlToDocAction(saveParams);
  // console.log('data: ', data);
  showLoading.value = false;
  if (!error) {
    const params: any = {
      catalogId: selectItem.value.id, // 目录id
      filePath: data, // 生成的标书文档地址
      wordNum: ueditor.value.getContentLength(true),
      tips: selectFormat.value.tips
    };

    showLoading.value = true;
    const { data: insertData, error: insertError } = await insertCatalogDataAction(params);
    showLoading.value = false;
    if (!insertError) {
      const defaultObj: any = {
        label: '当前版本',
        value: 1,
        filePath: selectFormat.value.filePath,
        tips: selectFormat.value.tips
      };
      formatOptions.value = [defaultObj];
      selectFormat.value = defaultObj;
      currentFormat.value = 1;

      successMessage('保存成功！');
    }
  }
}

// 获取编辑器中的所有图片
function getAllImagesInEditor() {
  const allImages = [];
  const imgTags = ueditor.value.document.getElementsByTagName('img');

  for (let i: number = 0; i < imgTags.length; i++) {
    const img = imgTags[i];
    if (img.src.includes('http://') || img.src.includes('https://')) {
      allImages.push(img);
    }
  }

  return allImages;
}

// 返回
function backClick() {
  isBack.value = true;
  routerBack();
}

onBeforeRouteLeave((to, from, next) => {
  isBack.value = true;
  next();
});
</script>

<template>
  <NLayout :native-scrollbar="false">
    <NSpin :show="showLoading" :description="loadingDes" :rotate="false" size="large">
      <template #icon>
        <img src="@/assets/imgs/spin-loading.gif" alt="" width="240" height="240" />
      </template>
      <div class="content-box">
        <div class="header-box">
          <div class="content-header">
            <div class="left-top">
              <span class="name-text">{{ fileName }}</span>
            </div>
            <div class="content-left">
              <div class="catalog-msg-box">
                <div class="right-top">
                  <span class="number-text">总章节：{{ docInfoObj.catalogNum || 0 }}</span>
                  <span class="number-text">已完成：{{ docInfoObj.finishNum || 0 }}</span>
                  <span class="number-text">总字数：{{ docInfoObj.wordNum || 0 }}</span>
                </div>
                <div class="tag-box">
                  <div v-for="item in writeTagList" :key="item.id" class="tag-item">
                    <img class="tag-img" :src="item.image" alt="" />
                    <span class="tag-title" :style="{ color: item.color }">{{ item.title }}</span>
                  </div>
                </div>
              </div>
              <NSpace>
                <NButton
                  class="format-btn"
                  strong
                  quaternary
                  :disabled="isOneClickWrite"
                  @click="setFormatAndPreviewClick"
                >
                  <template #icon>
                    <img src="@/assets/imgs/icon-format.png" width="16" alt="" />
                  </template>
                  设置格式并预览下载
                </NButton>
                <NButton class="write-btn" strong quaternary @click="backClick">
                  <NIcon size="20" color="#666666">
                    <ChevronBack />
                  </NIcon>
                  返回目录
                </NButton>
              </NSpace>
            </div>
          </div>
          <div class="shadow-line"></div>
        </div>
        <div class="content-body-box">
          <div class="catalog-data-box">
            <NScrollbar class="h-640px">
              <NDataTable
                :columns="columns"
                :data="catalogList"
                :row-key="(item: any) => item.id"
                max-height="100%"
                :expanded-row-keys="catalogRowKeys"
                default-expand-all
                striped
                :row-props="selectedRowKeysUpdate"
                @update:expanded-row-keys="expandedRowKeysUpdate"
              />
            </NScrollbar>
          </div>
          <div v-if="isBack" class="catalog-content-box z-1100 bg-white"></div>
          <div v-else class="catalog-content-box">
            <div class="title-tag-box">
              <span class="title-tag">当前位置：</span>
              <NTooltip trigger="hover">
                <template #trigger>
                  <span class="title-tag">{{ selectItem.title }}</span>
                </template>
                {{ selectItem.title }}
              </NTooltip>
            </div>
            <VueUeditorWrap
              v-model="contentHtml"
              editor-id="preview_editor"
              :config="editorConfig"
              :editor-dependencies="editorDependencies"
              @ready="readyHandle"
            />
            <div class="flex-y-center justify-between pb-10px pl-20px pr-20px pt-10px">
              <div class="direction-box">
                <div class="direction-content">
                  <span class="direction-title">编写方向：</span>
                  <span class="direction-msg">{{ selectFormat.tips || '暂无编写方向内容' }}</span>
                </div>
                <NButton class="direction-btn" @click="changeDirectionClick">修改</NButton>
                <NButton class="knowledge-btn ml-15px" @click="lookKnowledgeClick">知识库引用</NButton>
              </div>
              <NSpace justify="end">
                <NButton class="rewrite-btn" @click="rewriteClick">重新编写</NButton>
                <NSelect
                  v-model:value="currentFormat"
                  class="w-160px"
                  :options="formatOptions"
                  @update:value="formatChange"
                />
                <NButton class="save-btn" @click="saveClick">保存</NButton>
              </NSpace>
            </div>
          </div>
        </div>
      </div>
    </NSpin>
    <FormatModal v-model:show="showFormatModal" @save-format-setting="saveFormatSettingHandle" />
    <DownloadModal
      v-model:show="showDownloadModal"
      :task-id="taskId"
      :title="fileName"
      :catalog-num="docInfoObj.catalogNum"
      :format-obj="formatObj"
    />
    <WritingDirectionModal
      v-model:show="showDirectionModal"
      :direction="selectFormat.tips"
      @save-tips="saveTipsHandle"
    />
    <SelectImageDrawer v-model:visible="showImageDrawer" @confirm-image="insertFolderImageAction" />
    <KnowledgeModal v-model:show="showKnowledgeDrawer" :knowledge="knowledgeStr" />
  </NLayout>
</template>

<style scoped lang="scss">
.bg-layout {
  padding: 16px 16px 0 !important;
  background: url('@/assets/imgs/edit-bg.png');
  background-size: 100% 100%;
}
.content-box {
  background: rgba(229, 231, 253, 0.6);
  border-radius: 12px;
  border: 1px solid #faf9fd;
  padding: 40px 40px 0px 40px;
  margin: 17px 15px 0;
  position: sticky;
  top: 0;
}
:deep(.edui-editor) {
  width: auto !important;
}
:deep(.edui-editor-iframeholder) {
  width: auto !important;
}
:deep(.n-spin) {
  width: auto;
  height: auto;
}
:deep(.n-data-table-th__title) {
  font-weight: bold;
  font-size: 22px;
  color: #333333;
  padding: 0 30px;
}
.header-box {
  display: flex;
  flex-direction: column;
  background: rgba(229, 231, 253, 0.6);
  position: sticky;
  top: 0;
  z-index: 910;
  .content-header {
    display: flex;
    flex-direction: column;
    background-color: #ffffff;
    height: 122px;
    width: 100%;
    //box-shadow: 0px 0px 40px 0px rgba(131, 111, 255, 0.1);
    border-top-left-radius: 12px;
    border-top-right-radius: 12px;
    padding: 10px 30px;
    .left-top {
      display: flex;
      flex-direction: row;
      align-items: center;
      .name-text {
        font-weight: bold;
        font-size: 24px;
        color: #333333;
        line-height: 49px;
      }
      .name-img {
        width: 23px;
        height: 25px;
        margin-left: 15px;
        cursor: pointer;
      }
      .status-box {
        display: flex;
        flex-direction: row;
        align-items: center;
        margin-left: 100px;
        .status-img {
          width: 18px;
          height: 18px;
          margin-right: 5px;
        }
        .status-img-gif {
          width: 32px;
          height: 32px;
          margin-right: 5px;
        }
        .status-text {
          font-size: 16px;
          color: #0d6fb8;
        }
      }
    }
    .content-left {
      display: flex;
      flex-direction: row;
      justify-content: space-between;
      align-items: flex-start;
      .catalog-msg-box {
        display: flex;
        flex-direction: column;
        .right-top {
          display: flex;
          flex-direction: row;
          align-items: center;
          .number-text {
            margin-right: 25px;
            font-weight: 400;
            font-size: 16px;
            color: #666666;
            line-height: 30px;
          }
        }
        .tag-box {
          display: flex;
          flex-direction: row;
          align-items: center;
          margin-top: 5px;
          .tag-item {
            display: flex;
            flex-direction: row;
            align-items: center;
            margin-right: 20px;
            .tag-img {
              width: 12.5px;
              height: 12.5px;
              margin-right: 5px;
            }
            .tag-title {
              font-weight: 400;
              font-size: 12px;
            }
          }
        }
      }
      .format-btn {
        width: 180px;
        height: 40px;
        background: #ffffff;
        border-radius: 4px;
        border: 1px solid #836fff;
      }
      .write-btn {
        width: 130px;
        height: 40px;
        background: #ffffff;
        border-radius: 4px;
        border: 1px solid #836fff;
      }
    }
  }
  .shadow-line {
    width: 100%;
    height: 10px;
    background: linear-gradient(180deg, #a6b4ca 0%, rgba(166, 180, 202, 0.01) 69%);
  }
}
.content-body-box {
  display: flex;
  flex-direction: row;
  .catalog-data-box {
    width: 576px;
  }
  .catalog-content-box {
    background-color: #ffffff;
    width: calc(100% - 576px);
    position: relative;
    .title-tag-box {
      position: absolute;
      top: -55px;
      z-index: 910;
      .title-tag {
        display: inline-block;
        font-weight: 500;
        font-size: 18px;
        color: #333333;
        line-height: 30px;
        max-width: 400px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
    }
    .rewrite-btn {
      width: 150px;
      height: 34px;
      background: #ffffff;
      border-radius: 4px;
      border: 1px solid #836fff;
      font-weight: 400;
      font-size: 16px;
      color: #666666;
    }
    .save-btn {
      width: 100px;
      height: 34px;
      border-radius: 4px;
      font-weight: 400;
      font-size: 16px;
      color: #ffffff;
      background: linear-gradient(90deg, #e877ae 0%, #7c73f3 100%);
    }
  }
}
.direction-box {
  display: flex;
  flex-direction: row;
  align-items: center;
  .direction-content {
    display: flex;
    flex-direction: column;
    margin-right: 15px;
    .direction-title {
      font-weight: 400;
      font-size: 13px;
      color: #836fff;
      line-height: 18px;
    }
    .direction-msg {
      font-weight: 400;
      font-size: 13px;
      color: #333333;
      line-height: 18px;
      max-width: 120px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
  }
  .direction-btn {
    width: 64px;
    height: 30px;
    background: #ffffff;
    border-radius: 4px;
    border: 1px solid #836fff;
    font-weight: 400;
    font-size: 13px;
    color: #999999;
    line-height: 49px;
  }
  .knowledge-btn {
    width: 100px;
    height: 30px;
    background: #ffffff;
    border-radius: 4px;
    border: 1px solid #836fff;
    font-weight: 400;
    font-size: 13px;
    color: #999999;
    line-height: 49px;
  }
}
</style>
